/*
 * Copyright 2010-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jslet.paas.common;

import java.util.*;

/**
 * <code>IsoDate</code> is the utility class for dealing with ISO date bi-converting.
 * 
 * @author Tony Tong
 * @since jslet-paas 1.0
 */
public class IsoDate
{

	public static final int DATE = 1;

	public static final int TIME = 2;

	public static final int DATE_TIME = 3;

	static void dd(StringBuffer buf, int i)
	{
		buf.append((char) (((int) '0') + i / 10));
		buf.append((char) (((int) '0') + i % 10));
	}

	/***
	 * 
	 * Date to String.
	 * 
	 * @param date
	 * @param type possible value: IsoDate.DATE_TIME/IsoDate.DATE/IsoDate.TIME
	 * @return
	 */
	public static String dateToString(Date date, int type)
	{

		Calendar c = Calendar.getInstance();
		c.setTimeZone(TimeZone.getTimeZone("GMT"));
		c.setTime(date);

		StringBuffer buf = new StringBuffer();

		if ((type & DATE) != 0)
		{
			int year = c.get(Calendar.YEAR);
			dd(buf, year / 100);
			dd(buf, year % 100);
			buf.append('-');
			dd(buf, c.get(Calendar.MONTH) - Calendar.JANUARY + 1);
			buf.append('-');
			dd(buf, c.get(Calendar.DAY_OF_MONTH));

			if (type == DATE_TIME)
			{
				buf.append('T');
			}
		}

		if ((type & TIME) != 0)
		{
			dd(buf, c.get(Calendar.HOUR_OF_DAY));
			buf.append(':');
			dd(buf, c.get(Calendar.MINUTE));
			buf.append(':');
			dd(buf, c.get(Calendar.SECOND));
			buf.append('.');
			int ms = c.get(Calendar.MILLISECOND);
			buf.append((char) (((int) '0') + (ms / 100)));
			dd(buf, ms % 100);
			buf.append('Z');
		}

		return buf.toString();
	}

	/***
	 * 
	 * Convert String to Date.
	 * 
	 * @param text date string with Iso format
	 * @param type possible value: IsoDate.DATE_TIME/IsoDate.DATE/IsoDate.TIME
	 * @return
	 */
	public static Date stringToDate(String text, int type)
	{

		Calendar c = Calendar.getInstance();

		if ((type & DATE) != 0)
		{
			c.set(Calendar.YEAR, Integer.parseInt(text.substring(0, 4)));
			c.set(Calendar.MONTH, Integer.parseInt(text.substring(5, 7)) - 1 + Calendar.JANUARY);
			c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(text.substring(8, 10)));

			if (type != DATE_TIME || text.length() < 11)
			{
				c.set(Calendar.HOUR_OF_DAY, 0);
				c.set(Calendar.MINUTE, 0);
				c.set(Calendar.SECOND, 0);
				c.set(Calendar.MILLISECOND, 0);
				return c.getTime();
			}
			text = text.substring(11);
		}
		else
		{
			c.setTime(new Date(0));
		}

		c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(text.substring(0, 2)));
		// -11
		c.set(Calendar.MINUTE, Integer.parseInt(text.substring(3, 5)));
		c.set(Calendar.SECOND, Integer.parseInt(text.substring(6, 8)));

		int pos = 8;
		if (pos < text.length() && text.charAt(pos) == '.')
		{
			int msecord = 0;
			int f = 100;
			while (true)
			{
				char d = text.charAt(++pos);
				if (d < '0' || d > '9')
				{
					break;
				}
				msecord += (d - '0') * f;
				f /= 10;
			}
			c.set(Calendar.MILLISECOND, msecord);
		}
		else
		{
			c.set(Calendar.MILLISECOND, 0);
		}

		if (pos < text.length())
		{
			if (text.charAt(pos) == '+' || text.charAt(pos) == '-')
			{
				c.setTimeZone(TimeZone.getTimeZone("GMT" + text.substring(pos)));

			}
			else if (text.charAt(pos) == 'Z')
			{
				c.setTimeZone(TimeZone.getTimeZone("GMT"));
			}
			else
			{
				throw new RuntimeException("illegal time format!");
			}
		}

		return c.getTime();
	}
}
